package cn.tedu.luban.order.webapi.service.impl;

import cn.tedu.luban.attach.service.IAttachService;
import cn.tedu.luban.commons.enums.order.OrderStatusEnum;
import cn.tedu.luban.commons.exception.LubanServiceException;
import cn.tedu.luban.commons.pojo.attach.dto.AttachDTO;
import cn.tedu.luban.commons.pojo.attach.dto.AttachUpdateDTO;
import cn.tedu.luban.commons.pojo.attach.model.Attach;
import cn.tedu.luban.commons.pojo.order.dto.*;
import cn.tedu.luban.commons.pojo.order.model.Order;
import cn.tedu.luban.commons.pojo.order.model.OrderLog;
import cn.tedu.luban.commons.pojo.order.vo.*;
import cn.tedu.luban.commons.restful.JsonPage;
import cn.tedu.luban.commons.restful.ResponseCode;
import cn.tedu.luban.commons.utils.PropertiesUtils;
import cn.tedu.luban.demand.service.IRequestOrderService;
import cn.tedu.luban.order.service.EventService;
import cn.tedu.luban.order.service.IOrderService;
import cn.tedu.luban.order.webapi.mapper.OrderLogMapper;
import cn.tedu.luban.order.webapi.mapper.OrderMapper;
import cn.tedu.luban.order.webapi.utils.IncUidGenerator;
import cn.tedu.luban.order.webapi.utils.SecurityContext;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.netflix.ribbon.proxy.annotation.TemplateName;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderServiceImpl implements IOrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderLogMapper orderLogMapper;
    @Autowired
    private EventService eventService;

    @DubboReference
    private IAttachService dubboAttachService;

    @DubboReference
    private IRequestOrderService requestOrderService;

    @Autowired
    private IncUidGenerator incUidGenerator;

    @Value("${app.business.type}")
    private Integer businessType;

    @Value("${url}")
    private String url;

    // 详情
    @Override
    public OrderDetailVO getOrderByOrderNo(String orderNo) {
        // 订单基本信息
        Order order=orderMapper.getOrderByOrderNo(orderNo);
        OrderDetailVO orderDetailVO=new OrderDetailVO();
        // 订单图片
        orderDetailVO.setAttachInfo(getAttachList(order.getId()));

        //日志map
        Map<String, Long> operateTime = getOperateTime(orderNo);
        // OrderInfoVo赋值
        OrderInfoVo orderInfoVo=new OrderInfoVo();
        BeanUtils.copyProperties(order,orderInfoVo);
        orderInfoVo.setSignTime(operateTime.get(OrderStatusEnum.ORDER_SIGN_SUCCESS.getMessage()));
        orderInfoVo.setFinishTime(operateTime.get(OrderStatusEnum.ORDER_SERVICE_SUCCESS_UN_SETTLE.getMessage()));
        orderInfoVo.setCreateTime(order.getGmtCreate());
        orderDetailVO.setOrderInfo(orderInfoVo);
        // RequestOrderInfoVO赋值
        RequestOrderInfoVO requestOrderInfoVO=new RequestOrderInfoVO();
        BeanUtils.copyProperties(order,requestOrderInfoVO);
        requestOrderInfoVO.setRequestOrderCategoryName(order.getOrderCategoryName());
        orderDetailVO.setRequestOrderInfo(requestOrderInfoVO);
        // UserInfoVO赋值
        UserInfoVO userInfoVO=new UserInfoVO();
        BeanUtils.copyProperties(order,userInfoVO);
        orderDetailVO.setUserInfo(userInfoVO);

        return orderDetailVO;
    }

    // 列表
    @Override
    public JsonPage<OrderVO> list(OrderListDTO orderListDTO,Integer pageNo,Integer pageSize) {
        Long userId= SecurityContext.getUserId();
        orderListDTO.setUserId(userId);
        PageHelper.startPage(pageNo,pageSize);
        List<Order> orderList=orderMapper.queryOrders(orderListDTO);
        List<OrderVO> orderVOList=PropertiesUtils.copyListProperties(orderList,OrderVO.class);
        for (int i = 0; i <orderList.size() ; i++) {
            orderVOList.get(i).setRequestOrderCategoryName(
                    orderList.get(i).getOrderCategoryName());
        }
        return JsonPage.restPage(new PageInfo<>(orderVOList));
    }

    //签到
    @Override
    @Transactional
    public String sign(OrderSignDTO orderSignDTO) {
        Long userId= SecurityContext.getUserId();
        doUpdate(orderSignDTO.getOrderNo(),userId,OrderStatusEnum.ORDER_SIGN_SUCCESS);
        return orderSignDTO.getOrderNo();
    }


    @Override
    @Transactional
    public String create(OrderDTO orderDTO) {
        // 调用需求单模块抢单方法
        Integer num= (Integer) requestOrderService.grabOrder(orderDTO.getRequestOrderNo());
        if(num==0){
            throw new LubanServiceException(ResponseCode.NOT_ACCEPTABLE,"抢单失败");
        }
        Long userId=SecurityContext.getUserId();
        String orderNo=incUidGenerator.generate(userId);
        try {
            orderDTO.setUserId(userId);
            doCreate(orderNo,orderDTO);
        }catch (LubanServiceException e){
            // 出现异常发消息回滚
            OrderMqDTO orderMqDTO=new OrderMqDTO();
            BeanUtils.copyProperties(orderDTO,orderMqDTO);
            eventService.sendOrderCancelEvent(orderMqDTO);
            log.error("生成订单时发生错误",e);
            throw e;
        }

        return orderNo;
    }

    @Override
    public String confirm(OrderConfirmDTO orderConfirmDTO) {
        Order order=orderMapper.getOrderByOrderNo(orderConfirmDTO.getOrderNo());
        if(order==null){
            throw new LubanServiceException(ResponseCode.NOT_FOUND,"找不到订单");
        }
        createAttach(order.getId().intValue(),orderConfirmDTO.getAttachIds());

        return orderConfirmDTO.getOrderNo();
    }

    @Override
    @Transactional
    public String finish(OrderFinishDTO orderFinishDTO) {
        Long userId=SecurityContext.getUserId();
        Order order=doUpdate(orderFinishDTO.getOrderNo(), userId,
                OrderStatusEnum.ORDER_SERVICE_SUCCESS_UN_SETTLE);
        OrderMqDTO orderMqDTO=new OrderMqDTO();
        orderMqDTO.setWorkerId(order.getUserId());
        orderMqDTO.setRequestOrderCategoryName(order.getOrderCategoryName());
        BeanUtils.copyProperties(order,orderMqDTO);

        eventService.sendOrderFinishEvent(orderMqDTO);
        return orderFinishDTO.getOrderNo();
    }

    @Override
    public void finishOrder(String orderNo, Long userId) {
        doUpdate(orderNo,userId,OrderStatusEnum.ORDER_FINISH);
    }

    private void createAttach(int businessId, List<Long> attachIds) {
        List<AttachUpdateDTO> attachUpdateDTOList = new ArrayList<>();
        // attachIds 文件id 前端入参
        attachIds.forEach(id -> {
            AttachUpdateDTO attachUpdateDTO = new AttachUpdateDTO();
            attachUpdateDTO.setId(id.intValue());
            attachUpdateDTO.setBusinessId(businessId);
            attachUpdateDTO.setBusinessType(businessType);
            attachUpdateDTO.setIsCover(0);
            attachUpdateDTOList.add(attachUpdateDTO);
        });
        dubboAttachService.batchUpdateAttachByIdList(attachUpdateDTOList);
    }

    private void doCreate(String orderNo, OrderDTO orderDTO) {
        orderDTO.setOrderNo(orderNo);
        orderDTO.setStatus(OrderStatusEnum.ORDER_CREATE_SUCCESS.getStatus());

        // 日志
        OrderLog orderLog = new OrderLog();
        orderLog.setOrderNo(orderNo);
        orderLog.setUserId(orderDTO.getUserId());
        orderLog.setOperateName(OrderStatusEnum.ORDER_CREATE_SUCCESS.getMessage());
        orderLog.setRemark(OrderStatusEnum.ORDER_CREATE_SUCCESS.getMessage());
        long now = System.currentTimeMillis();
        orderLog.setOperateTime(now);
        orderLog.setGmtModified(now);
        orderLog.setGmtCreate(now);
        orderLog.setStatus(1);
        orderLog.setCreateUserId(orderDTO.getUserId());
        orderLog.setModifiedUserId(orderDTO.getUserId());
        orderLog.setCreateUserName("mock1");
        orderLog.setModifiedUserName("mock1");
        orderLogMapper.insert(orderLog);

        Order order=new Order();
        BeanUtils.copyProperties(orderDTO, order);
        order.setGmtCreate(System.currentTimeMillis());
        order.setGmtModified(order.getGmtCreate());
        order.setCreateUserId(orderDTO.getUserId());
        order.setModifiedUserId(orderDTO.getUserId());
        order.setCreateUserName("mock1");
        order.setModifiedUserName("mock1");
        orderMapper.insert(order);


    }

    private Order doUpdate(String orderNo, Long userId, OrderStatusEnum orderStatusEnum) {
        Order order=orderMapper.getOrderByOrderNo(orderNo);
        if(order==null || OrderStatusEnum.isErrorStatus(order.getStatus(),orderStatusEnum.getStatus())){
            throw new LubanServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"没有用户或订单状态不正确");
        }
        // 订单日志 信息
        OrderLog orderLog = new OrderLog();
        orderLog.setOrderNo(orderNo);
        orderLog.setUserId(userId);
        orderLog.setOperateName(orderStatusEnum.getMessage());
        orderLog.setRemark(orderStatusEnum.getMessage());
        long now = System.currentTimeMillis();
        orderLog.setOperateTime(now);
        orderLog.setGmtModified(now);
        orderLog.setGmtCreate(now);
        orderLog.setStatus(1);
        orderLog.setCreateUserId( userId);
        orderLog.setModifiedUserId(userId);
        orderLog.setCreateUserName("mock1");
        orderLog.setModifiedUserName("mock1");
        orderLogMapper.insert(orderLog);

        // 订单状态修改为签到
        order.setStatus(orderStatusEnum.getStatus());
        order.setGmtCreate(System.currentTimeMillis());
        order.setGmtModified(order.getGmtCreate());
        order.setCreateUserId(userId);
        order.setModifiedUserId(userId);
        order.setCreateUserName("mock1");
        order.setModifiedUserName("mock1");
        orderMapper.update(order);

        return order;
    }

    private List<AttachInfoVO> getAttachList(Long id) {

        AttachDTO attachDTO=new AttachDTO();
        attachDTO.setBusinessId(id.intValue());
        attachDTO.setBusinessType(businessType);
        List<Attach> attachList=dubboAttachService.getAttachInfo(attachDTO);
        List<AttachInfoVO> attachInfoVOs=new ArrayList<>();
        if(!attachList.isEmpty()){
            attachList.forEach(attach -> {
                AttachInfoVO attachInfoVO=new AttachInfoVO();
                attachInfoVO.setUrl(url+attach.getFileUuid());
                attachInfoVOs.add(attachInfoVO);
            });
        }
        return attachInfoVOs;

    }

    private Map<String,Long> getOperateTime(String orderNo){
        List<OrderLog> orderLogs = orderLogMapper.getOrderLogByOrderNo(orderNo);
        if (!CollectionUtils.isEmpty(orderLogs)){
            return orderLogs.stream()
                    .collect(Collectors.toMap(OrderLog::getOperateName, OrderLog::getOperateTime,(v1, v2)->v2));
        }
        return Collections.emptyMap();
    }
}
